﻿using Newtonsoft.Json.Linq;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace xhim.common.Helper
{
    public static class SignHelper
    {
        public static string FIELD_SIGN = "sign";

        // 设置请求重放的时间差
        private static long SIGN_EXPIRE = 1000 * 10;

        public static string verifySign(string appKey, string appSecret, string t, Dictionary<string, object> data)
        {
            // 参数判空，校验
            Console.WriteLine("传入的时间戳：{0}", t);
            if (null == appKey)
            {
                Console.WriteLine("没有传入appId");
                return "";
            }
            string nowTimeStamp = getTimeStamp();
            // 校验请求重放
            if (long.Parse(t) < long.Parse(nowTimeStamp) - SIGN_EXPIRE)
            {
                Console.WriteLine("sign失效！传入时间戳 {0}；当前时间戳：{1}", t, nowTimeStamp);
                return "";
            }
            // 根据请求，计算拼接参数，即data的拼接
            string objectFields = generateSignature(data, appKey);

            // 计算sign签名的值
            string tempSign = Md5Encrypt32(objectFields + appSecret + t);
            Console.WriteLine("计算出的sign：{0} {1}", objectFields, tempSign);
            // 校验传入的签名和服务端计算的签名是否一致，不一致则，签名认证失败

            return tempSign;
        }
        private static string generateSignature(Dictionary<string, object> data, string key)
        {
            try
            {
                var keySet = data.Keys.ToList().OrderBy(o => o);


                StringBuilder sb = new StringBuilder();
                foreach (string k in keySet)
                {
                    if (k.Equals(FIELD_SIGN))
                    {
                        continue;
                    }
                    //                if(sb.length()!=0){
                    //                    sb.append("&");
                    //                }
                    // 参数值为空，则不参与签名
                    if (data[k].ToString().Trim().Length > 0)
                    {
                        string v = urlEncodeUpper(data[k].ToString().Trim());
                        sb.Append(k).Append("=").Append(v).Append("&");
                    }
                }
                sb.Append(key);
                string souceString = sb.ToString();
                Console.WriteLine("参数按顺序拼接：{0}", souceString);
                return Md5Encrypt32(souceString);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return "";
        }

        public static string Md5Encrypt32(string source)
        {
            string rule = "";
            MD5 md5 = MD5.Create();
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(source));
            for (int i = 0; i < s.Length; i++)
            {
                rule += s[i].ToString("x2");
            }
            return rule;
        }


        public static string getTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }
        public static string urlEncodeUpper(string str)
        {
            StringBuilder builder = new StringBuilder();
            foreach (char c in str)
            {
                if (HttpUtility.UrlEncode(c.ToString(), Encoding.UTF8).Length > 1)
                {
                    builder.Append(HttpUtility.UrlEncode(c.ToString(), Encoding.UTF8).ToUpper());
                }
                else
                {
                    builder.Append(c);
                }
            }
            return builder.ToString().Replace(" ", "+");
        }


        public static string getSign(string appId, string appSecret, string t, Dictionary<string, object> data)
        {
            // 根据请求，计算拼接参数，即data的拼接
            string objectFields = generateSignature(data, appId);
            Log.Debug("计算出的sign：{objectFields}", objectFields);
            // 计算sign签名的值
            string tempSign = EncryptHelper.MD5Encrypt32(objectFields + appSecret + t).ToLower();
            return tempSign;
        }

    }
}
